package bajo.src;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import javax.microedition.io.HttpConnection;

import nanuk.exception.NanukException;
import net.rim.blackberry.api.browser.URLEncodedPostData;
import net.rim.device.api.collection.util.BasicFilteredList;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.FocusChangeListener;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.AutoCompleteField;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.PopupScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;
import net.rim.device.api.util.Arrays;

public class MainPage extends MainScreen implements FocusChangeListener {
	
	/* List of Course objects */
	private Vector courses;
	/* List of valid course codes received from the server */
	private String[] validCourseCodes; 
	private String userID;
	
	private final int COURSE_CODE_ID = 1;
	private final String COURSE_CODE_NAME = "valid course codes";
	private final String GREETING = "Press Enter to Insert a New Course.";
	
	/* UI components */
	private HorizontalFieldManager uiTabManager; // Used to manage the tabs.
	private HorizontalFieldManager uiAddPostManager; // Used to manage the adding post area.
	private HorizontalFieldManager uiCourseTitleManager; 
	private VerticalFieldManager uiTabManagerVer;
	private VerticalFieldManager uiPostManager; // Used to manage the posts.
	private LabelField addButtonTabText;	// Label for adding courses.
	private ButtonField addCourseButton; // Button in the tab to add new course.
	private CustomButton addPostButton;	// Button beside the text field to submit a post.
	private CustomButton removeCourseButton;
	public TextBoxField addPostTxt;	// TextField for adding post.
	
	private HorizontalFieldManager uiBottomManager; // Handles the posts and friends list.
	private VerticalFieldManager uiBottomLeftManager; // Handles the posts and add posts textfield.
	private VerticalFieldManager uiFriendListManager; // Lists the friends
	
	private ButtonField invitationButton;
	
	/* Used to know which course postings is on screen */
	private Course courseInFocus;
	/* Used to know uiAddPostManager has been applied on the screen */
	private boolean focusInit = true;
	
	Vector tempPosts;
	Vector tempPostListener;
	
	// keep track of users near
	Vector userProx;
	
	public MainPage(String userID){
		super(MainScreen.NO_HORIZONTAL_SCROLL|MainScreen.NO_VERTICAL_SCROLL);
		this.userID = userID; 
		courses = new Vector();
		uiTabManager = new HorizontalFieldManager(Manager.HORIZONTAL_SCROLL | Manager.HORIZONTAL_SCROLLBAR);
		uiTabManagerVer = new VerticalFieldManager();
		uiCourseTitleManager = new HorizontalFieldManager();
		uiPostManager = new VerticalFieldManager();
		uiBottomLeftManager = new VerticalFieldManager(Manager.VERTICAL_SCROLL | Manager.VERTICAL_SCROLLBAR) {
			// Sets the width of the manager.
			protected void sublayout(int width, int height) {
                super.sublayout(3 * (getScreen().getWidth() / 4), height);
            }
		};
		uiBottomManager = new HorizontalFieldManager();
		uiFriendListManager = new VerticalFieldManager(Manager.HIGHLIGHT_FOCUS | Manager.VERTICAL_SCROLL | Manager.VERTICAL_SCROLLBAR);
		
		// get the valid list of courses
		CallBack callBack = new CallBack(){
			public void function(String[] data){
				validCourseCodes = data;
			}
		};
		HTTPDataThread sendThread = new HTTPDataThread(Constants.BASE_TOMCAT_ADDR + Constants.OFFERED_COURSE_SERVLET,
				null, HttpConnection.GET, callBack, false);
		sendThread.start();

		removeCourseButton = new CustomButton("Remove Course", 100, 15);
		removeCourseButton.setFont(Font.getDefault().derive(Font.PLAIN, 14));
		removeCourseButton.setChangeListener(new FieldChangeListener() {
			public void fieldChanged(Field field, int context) {
				courses.removeElement(courseInFocus);
				courseInFocus = null;
				updateAll(true);
				
				//Remove the course from the database
				URLEncodedPostData postData = new URLEncodedPostData(URLEncodedPostData.DEFAULT_CHARSET, false);
				postData.append("userId", getUserId());
				postData.append("courseCode", courseInFocus.getCode());
				CallBack callBack = new CallBack(){
					public void function(String[] data){
						if(data[0].equals("1")){
							courses.removeElement(courseInFocus);
							courseInFocus = null;
							updateAll(true);
//							Dialog.alert("The course has been removed!");
						}else{
							Dialog.alert("The course has not been removed, Please try again");
						}
					}
				};
				HTTPDataThread sendThread = new HTTPDataThread(Constants.BASE_TOMCAT_ADDR + Constants.REMOVE_COURSE_SERVLET,
													postData, HttpConnection.POST, callBack, false);
				sendThread.start();
			}
		});
		
		addCourseButton = new ButtonField("+");
		addCourseButton.setChangeListener(new FieldChangeListener() {
			public void fieldChanged(Field field, int context) {
				if (field.equals(addCourseButton)){
					// Pop-up a dialog box and get the course code.
					popup();
				}
			}
		});

		invitationButton = new ButtonField("INVITE");
		invitationButton.setChangeListener(new FieldChangeListener() {
			
			public void fieldChanged(Field field, int context) {
			
				
			}
		});
		
		uiTabManager.add(addCourseButton);
		
		
		// Message when '+' tab is selected.
		addButtonTabText = new LabelField(GREETING);
		uiPostManager.add(addButtonTabText);
		
		// Code for managing UI of entering a post.
		addPostTxt = new TextBoxField(25, (2 * (Display.getWidth() / 3)) - 70, false);
		addPostButton = new CustomButton("POST", 50, 15);
		uiAddPostManager = new HorizontalFieldManager();
		uiAddPostManager.add(addPostTxt);
		uiAddPostManager.add(addPostButton);
		addPostButton.setFont(Font.getDefault().derive(Font.BOLD, 14));
		courseInFocus = null;
		final MainPage mp = this;
		addPostButton.setChangeListener(new FieldChangeListener() {
			public void fieldChanged(Field field, int context) {
				if (courseInFocus != null && addPostTxt.getText()!= "") {
					courseInFocus.updatePostDB(getUserId(), addPostTxt.getText(), mp);
					addPostTxt.setText("");
					updateAll(false);
					addPostTxt.setFocus();
				}
			}
		});
		
		//Load user course information
		String url = Constants.BASE_TOMCAT_ADDR + Constants.IS_TAKING_SERVLET;
		URLEncodedPostData postData = new URLEncodedPostData(URLEncodedPostData.DEFAULT_CHARSET, false);
		postData.append("userId", userID);
		final String tempUserID = userID;
		callBack = new CallBack(){
			public void function(String[] data){
				for(int i=0; i< data.length; i++){
					addNewCourse(new Course(data[i], tempUserID));
				}		
			}
		};
		sendThread = new HTTPDataThread(url, postData, HttpConnection.POST, callBack, false);
		sendThread.start();
		
		// Tab Manager.
		uiTabManagerVer.add(uiTabManager);
		uiTabManagerVer.add(new SeparatorField());
		
		// Bottom Half Managers.
		uiBottomLeftManager.add(uiPostManager);
		uiBottomManager.add(uiBottomLeftManager);
		uiBottomManager.add(new SeparatorField());
		uiBottomManager.add(uiFriendListManager);
		
		add(uiTabManagerVer);
		add(uiBottomManager);
		getProximityInfo();
	}
	
	/*
	 * Function that will add the new course requested by the user.
	 */
	public void addNewCourse(final Course c){
		// Add course info to the database
		String url = Constants.BASE_TOMCAT_ADDR + Constants.ADD_COURSE_SERVLET;
		URLEncodedPostData postData = new URLEncodedPostData(URLEncodedPostData.DEFAULT_CHARSET, false);
		postData.append("userId", userID);
		postData.append("courseCode",c.getCode());
		CallBack callBack = new CallBack(){
			public void function(String[] data){
				// Add to the tab.
				uiTabManager.add(c);
				courses.addElement(c);
				((Course)courses.lastElement()).setFocus();
				courseTab(c);		
			}
		};
		HTTPDataThread sendThread = new HTTPDataThread(url, postData, HttpConnection.POST, callBack, false);
		sendThread.start();
	}

	public void getProximityInfo(){
		// Ask control panel to perform Bluetooth proximity scan
     	try {
			AppMain.theApp.reportProximity();
		} catch (NanukException e) {
		}
		// get proximity information
		String url = Constants.BASE_TOMCAT_ADDR + Constants.GET_NEAR_USERS_ALL_SERVLET;
		URLEncodedPostData postData = new URLEncodedPostData(URLEncodedPostData.DEFAULT_CHARSET, false);
		postData.append("login", userID);
		postData.append("credentials", AppMain.userCredentials.getCredentials());
		postData.append("interval", "10");
		postData.append("sortByDate", "true");
		CallBack callBack = new CallBack(){
			public void function(String[] data){
				userProx = new Vector();
				// 4 strings per user
				// login, first name, last name, and profile photo URL.
				if (data.length >= 4){
					for (int i = 0; i < data.length;){
						userProx.addElement(new Student(data[i++], data[i++], data[i++], data[i++]));
					}
					updateProxUserInCourse();
				}
			}
		};
		HTTPDataThread sendThread = new HTTPDataThread(url, postData, HttpConnection.POST, callBack, false);
		sendThread.start();
	}
	
	/*
	 * This function is used to update the screen.
	 */
	public void updateAll(boolean removedCourse) {
		// Delete everything on the screen.
		delete(uiTabManagerVer);
		delete(uiBottomManager);
		uiBottomManager.deleteAll();
		uiBottomLeftManager.deleteAll();
		uiPostManager.deleteAll();
		uiFriendListManager.deleteAll();
		if (!focusInit) {
			uiCourseTitleManager.deleteAll();
		}
		focusInit = false;
		
		// Redisplay the tabs.
		uiTabManagerVer.deleteAll();
		uiTabManager.deleteAll();
		uiTabManager.add(addCourseButton);
		int index;
		for (index = 0; index < courses.size(); index++) {
			uiTabManager.add((Course) courses.elementAt(index));
		}
		uiTabManagerVer.add(uiTabManager);
		uiTabManagerVer.add(new SeparatorField());
		
		add(uiTabManagerVer);
		if (removedCourse) {
			// Do this if this function has been invoked from removing a course.
			focusInit = true;
			uiPostManager.add(new LabelField(GREETING));
			
			uiBottomLeftManager.add(uiPostManager);
		} else {
			// Do this otherwise.
			createPostManager();
			
			uiCourseTitleManager.add(new LabelField(courseInFocus.getCode()));
			uiCourseTitleManager.add(removeCourseButton);
			
			uiBottomLeftManager.add(uiCourseTitleManager);
			uiBottomLeftManager.add(uiPostManager);
			uiBottomLeftManager.add(uiAddPostManager);
			
			Hashtable students = courseInFocus.getEnrolledStudents();
			Enumeration keys = students.keys();
			
			while (keys.hasMoreElements()){
//				VerticalFieldManager studentAndStatusManager = new VerticalFieldManager();
				Student s = (Student)students.get(keys.nextElement());
//				studentAndStatusManager.add(s);
				//studentAndStatusManager.add();
				uiFriendListManager.add(s);
			}
		}
		
		// Adding the post managers.
		uiBottomManager.add(uiBottomLeftManager);
		uiBottomManager.add(new SeparatorField());
		uiBottomManager.add(uiFriendListManager);
		
		add(uiBottomManager);
		this.invalidate();
	}
	
	/*
	 * This function sets up the listeners for the course tabs.
	 */
	public void courseTab(Course c) {
		c.setChangeListener(new FieldChangeListener() {
			public void fieldChanged(Field field, int context) {
				if (field instanceof Course){
					// Let the phone know which course is in focus.
					courseInFocus = (Course) field;
					courseInFocus.updateStudents();
					courseInFocus.updatePostDB("", "", null);
					getProximityInfo();					
					// Update the screen.
					updateAll(false);
					courseInFocus.setFocus();
				}
			}
		});
	}
	
	public void updateProxUserInCourse(){
		Hashtable enrolledStudents = courseInFocus.getEnrolledStudents();
		Student s;
		for (int i = 0; i < userProx.size(); i++){
			s = (Student) userProx.elementAt(i);
			Student stu;
			stu = (Student) enrolledStudents.get(s.getID());
			if (stu != null){
				stu.setProx(true);
			}
			else{
				s.setProx(false);
				enrolledStudents.put(s.getID(), s);
			}
		}
	}
	
	/*
	 * Function where it return a VerticalFieldManager with all the posts
	 * related to the course.
	 */
	public void createPostManager(){
		tempPosts = courseInFocus.getPosts();
		tempPostListener = courseInFocus.getPostListener();
		
		uiPostManager.deleteAll();
		uiPostManager.add(new SeparatorField());
		
		int index;
		for (index = 0; index < tempPosts.size(); index++) {
			Post tempPost = (Post) tempPosts.elementAt(index);
			uiPostManager.add(tempPost.getPost());
			
			// Only add the remove post button if the current user added the post.
			if (userID.equals(tempPost.getPoster())) {
				tempPost.setFont(Font.getDefault().derive(Font.BOLD, 10));
				uiPostManager.add(tempPost);
				
				// Only initiate the listener once or else it will return a null
				// pointer exception.
				if (((Integer) tempPostListener.elementAt(index)).intValue() == 0) {
					tempPost.setChangeListener(new FieldChangeListener() {
						public void fieldChanged(final Field field, int context) {
							URLEncodedPostData postData = new URLEncodedPostData(URLEncodedPostData.DEFAULT_CHARSET, false);
							postData.append("userId", ((Post) field).getPoster());
							postData.append("postId", ((Post) field).getPostId());
							String url = Constants.BASE_TOMCAT_ADDR + Constants.REMOVE_POST_SERVLET;
							CallBack callBack = new CallBack(){
								public void function(String[] data){
									Vector tempPostsL = courseInFocus.getPosts();
									Vector tempPostListenerL = courseInFocus.getPostListener();
									
									tempPostListenerL.removeElementAt(tempPostsL.indexOf((Post) field));
									tempPostsL.removeElement((Post) field);
									
									courseInFocus.setPostVector(tempPostsL, tempPostListenerL);
									updateAll(false);
									addPostTxt.setFocus();
								}
							};
							HTTPDataThread sendThread = new HTTPDataThread(url, postData, HttpConnection.POST, callBack, false);
							sendThread.start();
						}
					});
					tempPostListener.setElementAt(new Integer(1), index);
				}
			}
			uiPostManager.add(new SeparatorField());
		}
		uiPostManager.invalidate();
	}
	
	/*
	 * Returns the String of the user's ID.
	 */
	private String getUserId(){
		return userID;
	}
	
	public void focusChanged(Field field, int eventType) {
	}
	
	/*
	 * This function will pop-up a dialog asking the user to input course code.
	 */
	public void popup(){
		CourseSelectionScreen popup = new CourseSelectionScreen();
		UiApplication.getUiApplication().pushScreen(popup);
	}

	/*
	 * Overridden function to get rid of the menu when switching to a 
	 * new main screen.
	 */
	public boolean onMenu(int instance) {
		return true;
	}

	/*
	 * Overridden function used to get rid of the save prompt
	 * when exiting the MainScreen.
	 */
	protected boolean onSavePrompt(){
		return true;
	}
	
	/*
	 * This class will handle all the pop-up dialog aspects: checking if the 
	 * course has been added already and the UI aspects of the dialog box.
	 */
	private class CourseSelectionScreen extends PopupScreen {
		private CourseSelectionScreen me = this;
		private BasicEditField _response;

		public CourseSelectionScreen() {
			super(new VerticalFieldManager(), Field.FOCUSABLE);
			
			LabelField question = new LabelField("Please enter the course code");
			BasicFilteredList filterCourseList = new BasicFilteredList();
			filterCourseList.addDataSet(COURSE_CODE_ID, validCourseCodes,
					COURSE_CODE_NAME, BasicFilteredList.COMPARISON_IGNORE_CASE);
			AutoCompleteField autoCompleteField = new AutoCompleteField(
					filterCourseList);
			_response = autoCompleteField.getEditField();
			
			// OK button.
			ButtonField okButton = new ButtonField("Ok");
			okButton.setChangeListener(new FieldChangeListener() {
				public void fieldChanged(Field field, int context) {
					// Add a new course.
					String courseCode = _response.getText();
					// Check if given course tab already exists.
					boolean found = false;
					
					for (int i = 0; i < courses.size(); i++){
						Course cour = (Course)courses.elementAt(i);
						if (cour.getCode().equals(courseCode)) {	
							cour.setFocus();
							found = true;
							break;
						}
					}
					// Check if given course code is a valid one.
					if (Arrays.contains(validCourseCodes, courseCode) && !found){
						Course newCourse = new Course(courseCode, userID);
						addNewCourse(newCourse);
					}
					UiApplication.getUiApplication().popScreen(me);
				}
			});
			
			// Cancel Button.
			ButtonField cancelButton = new ButtonField("Cancel");
			cancelButton.setChangeListener(new FieldChangeListener() {
				public void fieldChanged(Field field, int context) {
					UiApplication.getUiApplication().popScreen(me);
				}
			});
			
			HorizontalFieldManager buttonManager = new HorizontalFieldManager();
			buttonManager.add(okButton);
			buttonManager.add(cancelButton);

			add(question);
			add(new SeparatorField());
			add(autoCompleteField);
			add(buttonManager);
		}
	}
}